<?php

declare(strict_types=1);

namespace App\Middleware;

use App\Constants\Common\ApiStatusEnum;
use App\Constants\Menu\MenuMethodEnum;
use App\Constants\Menu\MenuStatusEnum;
use App\Constants\Menu\MenuTypeEnum;
use App\Constants\Role\RoleStatusEnum;
use App\Service\Access\MenuAccess;
use App\Service\Access\UserRoleAccess;
use Hyperf\Context\Context;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * 用户权限验证-中间件
 */
class UserPermissionMiddleware implements MiddlewareInterface
{
        /**
         * 过程处理
         * @param ServerRequestInterface $request
         * @param RequestHandlerInterface $handler
         * @return ResponseInterface
         */
        public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        {
                if (in_array($request->getAttribute('userId'), [1, 'xx'])) {#总管理员或xx直接验证通过
                        return $handler->handle($request);
                }
                $response = Context::get(ResponseInterface::class);
                $intMethod = array_flip(constantsEnumToKeyArray(MenuMethodEnum::cases()))[strtolower($request->getMethod())];
                $arrMenu = (new MenuAccess())->forPage([
                        'wheres' => [
                                'path' => $request->getUri()->getPath(),
                                'type' => MenuTypeEnum::DEFINITION_2->value,
                                'methods' => [$intMethod, MenuMethodEnum::DEFINITION_8->value],
                        ], 'fields' => ['menuId', 'status'], 'page' => 1, 'limit' => 10]);
                $arrMenuIds = [];
                $jsonReturn = json_encode(businessError(ApiStatusEnum::FORBIDDEN->getMessage(),
                        ApiStatusEnum::FORBIDDEN->value), JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
                foreach ($arrMenu as $v) {
                        if (intval($v['status']) === MenuStatusEnum::DEFINITION_2->value) {
                                return $response->withStatus(ApiStatusEnum::FORBIDDEN->value)->withBody(new SwooleStream($jsonReturn));
                        }
                        $arrMenuIds[] = $v['menuId'];
                }
                if (!$arrMenuIds) return $handler->handle($request);#不存在的权限验证直接通过
                $boolCheckPermission = (new UserRoleAccess())->exists([
                        'wheres' => [
                                'userId' => $request->getAttribute('userId'),
                                'menuIds' => $arrMenuIds,
                                'status' => RoleStatusEnum::DEFINITION_1->value,
                        ],
                        'joins' => [
                                [
                                        'table' => 'role',
                                        'on' => function ($join) {
                                                $join->on('role.roleId', '=', 'user_role.roleId');
                                        }
                                ],
                                [
                                        'table' => 'role_menu',
                                        'on' => function ($join) {
                                                $join->on('role_menu.roleId', '=', 'user_role.roleId');
                                        }
                                ],
                        ]
                ]);
                if (!$boolCheckPermission) {
                        return $response->withStatus(ApiStatusEnum::FORBIDDEN->value)->withBody(new SwooleStream($jsonReturn));
                }
                return $handler->handle($request);
        }
}